// ============================================================================
// 关键字爬取窗口管理服务 - 管理增量爬取时间窗口
// ============================================================================

import { Logger, logger } from '@roasmax/logger'
import { useEntityManager } from '../storage/data-source'
import { KeywordCrawlWindow } from '../storage/entities'

/**
 * 关键字爬取窗口管理服务
 */
export class KeywordCrawlWindowService {
  private static instance: KeywordCrawlWindowService

  private constructor() {}

  static getInstance(): KeywordCrawlWindowService {
    if (!KeywordCrawlWindowService.instance) {
      KeywordCrawlWindowService.instance = new KeywordCrawlWindowService()
    }
    return KeywordCrawlWindowService.instance
  }

  /**
   * 获取或创建关键字爬取窗口
   */
  async getOrCreateWindow(keyword: string): Promise<KeywordCrawlWindow> {
    return await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      
      let window = await repo.findOne({ where: { keyword } })
      
      if (!window) {
        window = new KeywordCrawlWindow()
        window.keyword = keyword
        window.hasMoreHistory = true
        window.totalPostsCrawled = 0
        window.latestPostsCrawled = 0
        window.historyPostsCrawled = 0
        
        await repo.save(window)
        
        logger.info('创建新的关键字爬取窗口', { 
          keyword, 
          windowId: window.keyword 
        })
      }
      
      return window
    })
  }

  /**
   * 更新关键字爬取窗口
   */
  async updateWindow(
    keyword: string, 
    newPosts: Array<{ created_at: string | Date }>, 
    type: 'latest' | 'history'
  ): Promise<KeywordCrawlWindow> {
    return await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      const window = await this.getOrCreateWindow(keyword)
      
      // 更新窗口
      window.updateWindow(newPosts, type)
      
      const updatedWindow = await repo.save(window)
      
      logger.info('更新关键字爬取窗口', {
        keyword,
        type,
        newPostsCount: newPosts.length,
        totalPosts: updatedWindow.totalPostsCrawled,
        hasMoreHistory: updatedWindow.hasMoreHistory,
        windowSize: updatedWindow.getWindowSizeDays()
      })
      
      return updatedWindow
    })
  }

  /**
   * 获取关键字的爬取时间范围
   * 返回格式适用于 searchWeiboByKeyword
   */
  async getSearchTimeRanges(keyword: string): Promise<{
    latestRange?: { startTime: string; endTime: string }
    historyRange?: { startTime?: string; endTime: string }
    shouldCrawlHistory: boolean
  }> {
    const window = await this.getOrCreateWindow(keyword)
    logger.info(JSON.stringify(window))
    const now = new Date()
    
    // 格式化为微博搜索需要的格式：YYYY-MM-DD-HH
    const formatTime = (date: Date): string => {
      const year = date.getFullYear()
      const month = String(date.getMonth() + 1).padStart(2, '0')
      const day = String(date.getDate()).padStart(2, '0')
      const hour = String(date.getHours()).padStart(2, '0')
      return `${year}-${month}-${day}-${hour}`
    }
    
    const result: any = {}
    
    // 最新帖子时间范围：从 endTime 到现在
    if (window.endTime) {
      result.latestRange = {
        startTime: formatTime(window.endTime),
        endTime: formatTime(now)
      }
    } else {
      // 如果没有历史数据，从现在开始爬取
      result.latestRange = {
        startTime: formatTime(new Date(now.getTime() - 24 * 60 * 60 * 1000)), // 24小时前
        endTime: formatTime(now)
      }
    }
    
    // 历史帖子时间范围：只传入 endTime
    result.shouldCrawlHistory = window.shouldCrawlHistory()
    if (result.shouldCrawlHistory && window.startTime) {
      result.historyRange = {
        endTime: formatTime(window.startTime)
      }
    } else if (result.shouldCrawlHistory && !window.startTime) {
      // 如果没有起始时间，从微博上线时间开始
      result.historyRange = {
        startTime: '2009-08-16-0',
        endTime: formatTime(new Date(now.getTime() - 24 * 60 * 60 * 1000))
      }
    }
    
    return result
  }

  /**
   * 检查关键字是否需要历史爬取
   */
  async shouldCrawlHistory(keyword: string, historyCrawlInterval: number = 24 * 60 * 60 * 1000): Promise<boolean> {
    const window = await this.getOrCreateWindow(keyword)
    return window.shouldCrawlHistory(historyCrawlInterval)
  }

  /**
   * 重置关键字窗口
   */
  async resetWindow(keyword: string): Promise<KeywordCrawlWindow> {
    return await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      const window = await this.getOrCreateWindow(keyword)
      
      window.reset()
      const resetWindow = await repo.save(window)
      
      logger.info('重置关键字爬取窗口', { keyword })
      
      return resetWindow
    })
  }

  /**
   * 获取所有关键字窗口摘要
   */
  async getAllWindowsSummary(): Promise<Array<{
    keyword: string
    windowSize: string
    totalPosts: number
    hasMoreHistory: boolean
    lastUpdate: string
  }>> {
    return await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      const windows = await repo.find({
        order: { updatedAt: 'DESC' }
      })
      
      return windows.map(window => window.getSummary())
    })
  }

  /**
   * 删除关键字窗口
   */
  async deleteWindow(keyword: string): Promise<void> {
    await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      await repo.delete({ keyword })
      
      logger.info('删除关键字爬取窗口', { keyword })
    })
  }

  /**
   * 获取窗口详情
   */
  async getWindowDetails(keyword: string): Promise<KeywordCrawlWindow | null> {
    return await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      return await repo.findOne({ where: { keyword } })
    })
  }

  /**
   * 批量更新窗口设置
   */
  async updateWindowSettings(keyword: string, updates: {
    hasMoreHistory?: boolean
    startTime?: Date
    endTime?: Date
  }): Promise<KeywordCrawlWindow> {
    return await useEntityManager(async (manager) => {
      const repo = manager.getRepository(KeywordCrawlWindow)
      const window = await this.getOrCreateWindow(keyword)
      
      if (updates.hasMoreHistory !== undefined) {
        window.hasMoreHistory = updates.hasMoreHistory
      }
      if (updates.startTime !== undefined) {
        window.startTime = updates.startTime
      }
      if (updates.endTime !== undefined) {
        window.endTime = updates.endTime
      }
      
      const updatedWindow = await repo.save(window)
      
      logger.info('更新关键字窗口设置', { keyword, updates })
      
      return updatedWindow
    })
  }

  /**
   * 获取需要历史爬取的关键字
   */
  async getKeywordsNeedingHistoryCrawl(historyCrawlInterval: number = 24 * 60 * 60 * 1000): Promise<string[]> {
    try {
      logger.debug('开始获取需要历史爬取的关键字', { historyCrawlInterval })
      
      return await useEntityManager(async (manager) => {
        logger.debug('获取EntityManager成功，开始查询数据库')
        
        const repo = manager.getRepository(KeywordCrawlWindow)
        logger.debug('获取Repository成功，执行查询')
        
        let windows: KeywordCrawlWindow[] = []
        
        try {
          // 先试用 boolean 值查询
          windows = await repo.find({
            where: { hasMoreHistory: true }
          })
          
          logger.debug('使用 boolean 查询成功', { 
            totalWindows: windows.length,
            windowKeywords: windows.map(w => w.keyword)
          })
        } catch (booleanQueryError) {
          logger.warn('使用 boolean 查询失败，尝试使用整数查询', {
            error: booleanQueryError instanceof Error ? booleanQueryError.message : String(booleanQueryError)
          })
          
          try {
            // 如果 boolean 查询失败，尝试使用整数查询 (SQLite 可能将 boolean 存储为 0/1)
            windows = await repo.createQueryBuilder('window')
              .where('window.has_more_history = :value', { value: 1 })
              .getMany()
              
            logger.debug('使用整数查询成功', { 
              totalWindows: windows.length,
              windowKeywords: windows.map(w => w.keyword)
            })
          } catch (integerQueryError) {
            logger.error('所有查询方式都失败', {
              booleanError: booleanQueryError instanceof Error ? booleanQueryError.message : String(booleanQueryError),
              integerError: integerQueryError instanceof Error ? integerQueryError.message : String(integerQueryError)
            })
            
            // 最后尝试获取所有记录并过滤
            const allWindows = await repo.find()
            windows = allWindows.filter(w => w.hasMoreHistory)
            
            logger.debug('使用内存过滤获取结果', {
              allWindowsCount: allWindows.length,
              filteredWindowsCount: windows.length
            })
          }
        }
        
        const now = new Date()
        const needingCrawl = windows.filter(window => {
          if (!window.lastHistoryCrawlAt) {
            logger.debug('窗口从未执行历史爬取', { keyword: window.keyword })
            return true
          }
          const timeSinceLastCrawl = now.getTime() - window.lastHistoryCrawlAt.getTime()
          const needsCrawl = timeSinceLastCrawl >= historyCrawlInterval
          return needsCrawl
        })
        
        const keywords = needingCrawl.map(window => window.keyword)
        logger.debug('历史爬取关键字筛选完成', {
          needingCrawlCount: needingCrawl.length,
          keywords
        })
        
        return keywords
      })
    } catch (error) {
      logger.error('获取需要历史爬取的关键字失败', {
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
        historyCrawlInterval
      })
      throw error
    }
  }
}

/**
 * 全局关键字爬取窗口服务实例
 */
export const keywordCrawlWindowService = KeywordCrawlWindowService.getInstance()
